package com.zbkj.service.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zbkj.common.exception.AppException;
import com.zbkj.common.model.admin.SystemAdmin;
import com.zbkj.common.model.brand.Brand;
import com.zbkj.common.model.merchant.Merchant;
import com.zbkj.common.model.traceability.Batches;
import com.zbkj.common.model.traceability.TraceableItems;
import com.zbkj.common.page.CommonPage;
import com.zbkj.common.request.PageParamRequest;
import com.zbkj.common.response.traceability.TraceableItemWithBatchResponse;
import com.zbkj.common.utils.IdGenerator;
import com.zbkj.service.dao.traceability.TraceableItemsDao;
import com.zbkj.service.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 可追溯项Service实现类
 * +----------------------------------------------------------------------
 * | CRMEB [ CRMEB赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 * | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
 * +----------------------------------------------------------------------
 * | Licensed CRMEB并不是自由软件，未经许可不能去掉CRMEB相关版权
 * +----------------------------------------------------------------------
 * | Author: xiaolic
 * +----------------------------------------------------------------------
 */
@Service
public class TraceableItemsServiceImpl extends ServiceImpl<TraceableItemsDao, TraceableItems> implements TraceableItemsService {

    @Resource
    private TraceableItemsDao traceableItemsDao;
    
    @Autowired
    private BatchesService batchesService;

    @Autowired
    private MerchantService merchantService;

    @Autowired
    private SystemAdminService systemAdminService;

    @Autowired
    private BrandService brandService;
    
    @Value("${site.url:pages/merchant/source/detail}")
    private String siteUrl;
    
    /**
     * 为批次生成可追溯项记录
     * @param batchId 批次ID
     * @return 生成结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean generateForBatch(Long batchId) {
        // 查询批次信息
        Batches batch = batchesService.getDetail(batchId);
        if (batch == null) {
            throw new AppException("批次不存在");
        }
        
        // 检查是否已经生成过
        LambdaQueryWrapper<TraceableItems> checkWrapper = new LambdaQueryWrapper<>();
        checkWrapper.eq(TraceableItems::getBatchId, batchId);
        checkWrapper.eq(TraceableItems::getIsDeleted, 0);
        long count = traceableItemsDao.selectCount(checkWrapper);
        if (count > 0) {
            throw new AppException("该批次已生成过可追溯项");
        }

        // 更新批次状态为生产中
        batchesService.update(
            new LambdaUpdateWrapper<Batches>()
                .set(Batches::getStatus, 1)
                .set(Batches::getUpdatedAt, new Date())
                .eq(Batches::getId, batchId)
        );

        String prefixUrl = "https://";
        Merchant merchant = merchantService.getById(batch.getMerchantId());
        if (merchant != null && merchant.getBrandId() > 0) {
            SystemAdmin systemAdmin = systemAdminService.getById(merchant.getBrandId());
            if (systemAdmin != null && systemAdmin.getBrandId() > 0) {
                Brand brand = brandService.getById(systemAdmin.getBrandId());
                if (brand != null && brand.getId() > 0) {
                    prefixUrl += brand.getShareUrl();
                }
            }
        }

        String url = prefixUrl + "/" + siteUrl + "?id=" + batch.getProductId()
                + "&batchId=" + batch.getId();

        try {
            // 获取序列号范围
            Long startSerial = batch.getStartSerial();
            Long endSerial = batch.getEndSerial();
            
            // 分批处理，每批次500条记录
            int batchSize = 500;
            Long currentStart = startSerial;
            
            while (currentStart <= endSerial) {
                // 计算当前批次的结束位置
                Long currentEnd = Math.min(currentStart + batchSize - 1, endSerial);
                
                // 准备当前批次的记录
                List<TraceableItems> itemsBatch = new ArrayList<>(batchSize);
                Set<Long> usedTraceIds = new HashSet<>(batchSize); // 跟踪已使用的ID，确保不会重复
                
                for (Long serialNumber = currentStart; serialNumber <= currentEnd; serialNumber++) {
                    // 生成唯一ID，确保不重复
                    Long traceId;
                    do {
                        traceId = IdGenerator.next();
                    } while (!usedTraceIds.add(traceId)); // 如果添加失败说明重复了，重新生成
                    
                    TraceableItems item = new TraceableItems();
                    item.setBatchId(batchId);
                    item.setSerialNumber(serialNumber);
                    item.setProductionDate(batch.getProductionDate());
                    item.setScanCount(0);
                    item.setTraceId(traceId);
                    item.setQrCodeUrl(url + "&traceId=" + traceId);
                    item.setCreatedAt(new Date()); // 使用最新时间，而不是批次开始时的时间
                    item.setUpdatedAt(new Date());
                    
                    itemsBatch.add(item);
                    
                    // 每生成100个ID暂停一下，避免过快生成导致时间戳相同
                    if (itemsBatch.size() % 100 == 0) {
                        try {
                            Thread.sleep(1); // 暂停1毫秒
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                }
                
                // 批量保存当前批次
                saveBatch(itemsBatch);
                
                // 更新下一批次的起始位置
                currentStart = currentEnd + 1;
            }
            
            // 更新批次状态为已完成
            batchesService.update(
                new LambdaUpdateWrapper<Batches>()
                    .set(Batches::getStatus, 2)
                    .set(Batches::getUpdatedAt, new Date())
                    .eq(Batches::getId, batchId)
            );
            
            return true;
        } catch (Exception e) {
            // 发生异常时，回滚批次状态为待处理
            batchesService.update(
                new LambdaUpdateWrapper<Batches>()
                    .set(Batches::getStatus, 0)
                    .set(Batches::getUpdatedAt, new Date())
                    .eq(Batches::getId, batchId)
            );
            
            throw new AppException("生成可追溯项失败: " + e.getMessage());
        }
    }

    /**
     * 分页查询可追溯项列表
     * @param batchId 批次ID
     * @param request 分页请求参数
     * @return 分页结果
     */
    @Override
    public PageInfo<TraceableItems> getPageList(Long batchId, PageParamRequest request) {
        LambdaQueryWrapper<TraceableItems> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TraceableItems::getBatchId, batchId);
        queryWrapper.eq(TraceableItems::getIsDeleted, 0);
        queryWrapper.orderByAsc(TraceableItems::getSerialNumber);
        
        // 使用PageHelper进行分页
        Page<TraceableItems> page = PageHelper.startPage(request.getPage(), request.getLimit());
        List<TraceableItems> items = traceableItemsDao.selectList(queryWrapper);
        
        if (CollUtil.isEmpty(items)) {
            return CommonPage.copyPageInfo(page, CollUtil.newArrayList());
        }

        for (TraceableItems item : items) {
            if (StrUtil.isNotBlank(item.getQrCodeUrl())) {
                BufferedImage bufferedImage = batchesService.generateQrCodePicWithTraceId(item.getQrCodeUrl(), item.getTraceId().toString());
                try {
                    item.setQrCodePic(bufferedImageToBase64(bufferedImage, "png"));
                } catch (IOException e) {
                    log.error("二维码图片转换为Base64失败：traceId=" + item.getTraceId(), e);
                }
            }
        }
        
        // 返回分页结果
        return CommonPage.copyPageInfo(page, items);
    }

    /**
     * 将BufferedImage转换为Base64字符串
     * @param image 图像对象
     * @param format 图像格式（如"png"、"jpg"等）
     * @return Base64编码的字符串
     * @throws IOException 如果转换过程中发生IO异常
     */
    private String bufferedImageToBase64(BufferedImage image, String format) throws IOException {
        // 创建一个字节数组输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        try {
            // 将图像写入到输出流
            ImageIO.write(image, format, outputStream);

            // 获取字节数组
            byte[] imageBytes = outputStream.toByteArray();

            // 使用Base64进行编码
            String base64String = Base64.getEncoder().encodeToString(imageBytes);

            // 返回带有前缀的完整Base64字符串（可用于HTML的img标签src属性）
            return "data:image/" + format + ";base64," + base64String;
        } finally {
            // 确保关闭输出流
            outputStream.close();
        }
    }

    /**
     * 获取可追溯项详情
     * @param id 可追溯项ID
     * @return 可追溯项详情
     */
    @Override
    public TraceableItems getDetail(Long id) {
        LambdaQueryWrapper<TraceableItems> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TraceableItems::getId, id);
        queryWrapper.eq(TraceableItems::getIsDeleted, 0);
        return getOne(queryWrapper);
    }

    /**
     * 根据批次ID和序列号获取可追溯项详情
     * @param batchId 批次ID
     * @param serialNumber 序列号
     * @return 可追溯项详情
     */
    @Override
    public TraceableItems getByBatchAndSerial(Long batchId, Long serialNumber) {
        LambdaQueryWrapper<TraceableItems> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TraceableItems::getBatchId, batchId);
        queryWrapper.eq(TraceableItems::getSerialNumber, serialNumber);
        queryWrapper.eq(TraceableItems::getIsDeleted, 0);
        
        return traceableItemsDao.selectOne(queryWrapper);
    }
    
    /**
     * 根据唯一溯源ID获取可追溯项
     * @param traceId 唯一溯源ID
     * @return 可追溯项详情
     */
    @Override
    public TraceableItems getByTraceId(Long traceId) {
        LambdaQueryWrapper<TraceableItems> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TraceableItems::getTraceId, traceId);
        queryWrapper.eq(TraceableItems::getIsDeleted, 0);
        
        return traceableItemsDao.selectOne(queryWrapper);
    }

    /**
     * 增加访问计数
     * @param id 可追溯项ID
     * @return 增加结果
     */
    @Override
    public Boolean incrementScanCount(Long id) {
        return incrementScanCount(id, null);
    }
    
    /**
     * 增加唯一溯源ID的访问计数
     * @param traceId 唯一溯源ID
     * @return 增加结果
     */
    @Override
    public Boolean incrementScanCountByTraceId(Long traceId) {
        return incrementScanCount(null, traceId);
    }
    
    /**
     * 内部方法：增加访问计数
     * @param id 可追溯项ID
     * @param traceId 唯一溯源ID
     * @return 增加结果
     */
    private Boolean incrementScanCount(Long id, Long traceId) {
        LambdaUpdateWrapper<TraceableItems> updateWrapper = new LambdaUpdateWrapper<>();
        if (id != null) {
            updateWrapper.eq(TraceableItems::getId, id);
        } else if (traceId != null) {
            updateWrapper.eq(TraceableItems::getTraceId, traceId);
        } else {
            return false;
        }
        
        updateWrapper.setSql("scan_count = scan_count + 1");
        updateWrapper.set(TraceableItems::getUpdatedAt, new Date());
        updateWrapper.eq(TraceableItems::getIsDeleted, 0);
        
        return update(updateWrapper);
    }

    /**
     * 生成二维码
     * @param traceableItem 可追溯项
     * @return 二维码URL
     */
    @Override
    public String generateQrCode(TraceableItems traceableItem) {
        // 这里只返回二维码链接，实际生成二维码图片可以在Controller层实现
        return traceableItem.getQrCodeUrl();
    }
    
    /**
     * 根据产品ID分页查询所有批次下的可追溯项
     * @param productId 产品ID
     * @param request 分页参数
     * @return 带有批次信息的可追溯项列表
     */
    @Override
    public PageInfo<TraceableItemWithBatchResponse> getPageListByProductId(Integer productId, PageParamRequest request) {
        // 1. 首先查询产品关联的所有未删除的批次
        LambdaQueryWrapper<Batches> batchesQueryWrapper = new LambdaQueryWrapper<>();
        batchesQueryWrapper.eq(Batches::getProductId, productId);
        batchesQueryWrapper.eq(Batches::getIsDeleted, 0);
        List<Batches> batches = batchesService.list(batchesQueryWrapper);
        
        if (CollUtil.isEmpty(batches)) {
            return new PageInfo<>();
        }
        
        // 2. 获取所有批次ID列表
        List<Long> batchIds = batches.stream().map(Batches::getId).collect(Collectors.toList());
        
        // 3. 使用PageHelper分页查询所有批次下的可追溯项
        Page<TraceableItemWithBatchResponse> page = PageHelper.startPage(request.getPage(), request.getLimit());
        
        // 4. 构建查询条件 - 需要关联两个表，使用原生方式（不使用LambdaQueryWrapper）
        List<TraceableItemWithBatchResponse> resultList = traceableItemsDao.getTraceableItemsWithBatchInfo(batchIds);
        
        if (CollUtil.isEmpty(resultList)) {
            return CommonPage.copyPageInfo(page, CollUtil.newArrayList());
        }
        
        // 5. 返回分页结果
        return CommonPage.copyPageInfo(page, resultList);
    }
}
